#include "robotsliderview.h"

RobotSliderView::RobotSliderView(QWidget *parent) :
    QWidget(parent),
    _model(NULL),
    _editCommand(NULL),
    _undoEnabled(true)
{
    //Set up the basic UI - a scroll area for
    //the sliders
    QVBoxLayout* layout = new QVBoxLayout();
    _scrollArea = new QScrollArea(this);
    layout->addWidget(_scrollArea);
    layout->setMargin(0);
    this->setLayout(layout);
}

void RobotSliderView::loadModel(Robot *robot){
    if(_model != NULL)
        delete _model;

    _model = robot;

    //Create all of the sliders for the model
    createSliders();

    //Listen to the model for changes to the joints
    connect(_model, SIGNAL(jointAngleChanged(int,float,float)),
            this, SLOT(onJointAngleChanged(int,float,float)));
}


QList< QPair <int, float> > RobotSliderView::values() const{
    int i;
    EditSlider* curSlider;
    QList<int> jointIDs = _model->jointIDs();
    QList< QPair<int, float> > retList;
    QPair<int,float> curPair;

    for(i = 0; i < jointIDs.length(); i++){
        curSlider = _scrollArea->widget()->findChild<EditSlider*>(QString::number(jointIDs.at(i)) + "_slider");
        curPair.first = jointIDs[i];
        curPair.second = curSlider->value();
        retList.append(curPair);
    }

    return retList;
}


void RobotSliderView::createSliders(){
    int i, curJointID;
    //The container widget and layout for the
    //scroll area
    QWidget* container = new QWidget();
    QFormLayout* layout = new QFormLayout();
    //The EditSlider widget for each slider
    EditSlider* slider;
    QLabel* nameLabel;

    //Cycle through each joint of the robot and
    //create a slider for it
    const QList<int> jointIDs = _model->jointIDs();
    for(i = 0; i < jointIDs.length(); i++){
        curJointID = jointIDs[i];

        slider = new EditSlider();
        slider->setRange(_model->minimum(curJointID), _model->maximum(curJointID));
        slider->setObjectName(QString::number(curJointID) + "_slider");

        //Listen to events from the slider
        connect(slider, SIGNAL(valueChanged(int)),
                this, SLOT(onSliderValueChanged(int)));
        connect(slider, SIGNAL(editingFinished(int)),
                this, SLOT(onSliderEditFinished(int)));

        nameLabel = new QLabel(_model->jointDescription(curJointID));
        nameLabel->setObjectName(QString::number(curJointID) + "_label");

        layout->addRow(nameLabel, slider);
    }

    //Set the layout and container for the scroll area
    container->setLayout(layout);
    _scrollArea->setWidget(container);
}


void RobotSliderView::show(int jointID){
    QList<int> temp;
    temp.append(jointID);
    show(temp);
}

void RobotSliderView::show(const QList<int> &jointIDs){
    int i;
    QList< QPair<QLabel*,EditSlider*> > sliderPairs;
    sliderPairs = getSliderPairs(jointIDs);

    for(i = 0; i < sliderPairs.length(); i++){
        sliderPairs[i].first->show();
        sliderPairs[i].second->show();
    }
}

void RobotSliderView::showAll(){
    show(_model->jointIDs());
}

void RobotSliderView::hide(int jointID){
    QList<int> temp;
    temp.append(jointID);
    hide(temp);
}

void RobotSliderView::hide(const QList<int> &jointIDs){
    int i;
    QList< QPair<QLabel*,EditSlider*> > sliderPairs;
    sliderPairs = getSliderPairs(jointIDs);

    for(i = 0; i < sliderPairs.length(); i++){
        sliderPairs[i].first->hide();
        sliderPairs[i].second->hide();
    }

}

void RobotSliderView::hideAll(){
    hide(_model->jointIDs());
}


void RobotSliderView::disable(int jointID){
    QList<int> temp;
    temp.append(jointID);
    disable(temp);
}

void RobotSliderView::disable(const QList<int> &jointIDs){
    int i;
    QList< QPair<QLabel*,EditSlider*> > sliderPairs;
    sliderPairs = getSliderPairs(jointIDs);

    for(i = 0; i < sliderPairs.length(); i++){
        sliderPairs[i].first->setDisabled(true);
        sliderPairs[i].second->setDisabled(true);
    }
}

void RobotSliderView::disableAll(){
    disable(_model->jointIDs());
}

void RobotSliderView::enable(int jointID){
    QList<int> temp;
    temp.append(jointID);
    enable(temp);
}

void RobotSliderView::enable(const QList<int> &jointIDs){
    int i;
    QList< QPair<QLabel*,EditSlider*> > sliderPairs;
    sliderPairs = getSliderPairs(jointIDs);

    for(i = 0; i < sliderPairs.length(); i++){
        sliderPairs[i].first->setEnabled(true);
        sliderPairs[i].second->setEnabled(true);
    }
}

void RobotSliderView::enableAll(){
    enable(_model->jointIDs());
}

void RobotSliderView::enableUndo(bool enabled){
    _undoEnabled = enabled;
}


QList< QPair<QLabel*,EditSlider*> > RobotSliderView::getSliderPairs(const QList<int> &jointIDs){
    int i;
    EditSlider* curSlider;
    QLabel* curLabel;
    QList< QPair<QLabel*,EditSlider*> > retList;
    QPair<QLabel*,EditSlider*> curPair;

    for(i = 0; i < jointIDs.length(); i++){
        curSlider = _scrollArea->widget()->findChild<EditSlider*>(QString::number(jointIDs.at(i)) + "_slider");
        curLabel = _scrollArea->widget()->findChild<QLabel*>(QString::number(jointIDs.at(i)) + "_label");
        if(curSlider != NULL && curLabel != NULL){
            curPair.first = curLabel;
            curPair.second = curSlider;
            retList.append(curPair);
        }
    }

    return retList;
}


//TODO: Is it okay to allow direct access to the joints?  If so, I need to
//redo the robot model
void RobotSliderView::onJointAngleChanged(int jointID, float newVal, float oldVal){
    //Grab the slider (who's object name is set to the jointID)
    EditSlider* slider = _scrollArea->findChild<EditSlider*>(QString::number(jointID) + "_slider");
    if(slider){
        //Block the signals from the slider so that onSliderValueChanged
        //isn't getting called
        slider->blockSignals(true);
        slider->setValue((int)newVal);
        slider->blockSignals(false);
    }
}

void RobotSliderView::onSliderValueChanged(int newVal){
    EditSlider* slider = (EditSlider*)sender();
    QString croppedName = slider->objectName();
    croppedName.chop(7);

    //Get the jointID from the slider's object name;
    int jointID = croppedName.toInt();

    //Get the new value, and bundle it into a robot command
    SetRobotJointCommand* command = new SetRobotJointCommand(_model, jointID, newVal);

    //Insert the command into the _editCommand group
    if(_editCommand == NULL)
        _editCommand = new RobotCommandGroup(_model);
    _editCommand->append(command);

    command->execute();
}

void RobotSliderView::onSliderEditFinished(int newVal){
    //Editing is finished.  Insert the edit command into the history
    if(_editCommand != NULL && _undoEnabled){
        _editCommand->setHistoryTip(tr("Set Robot Joint"));
        History::instance()->push(_editCommand);
        _editCommand = NULL;
    }
}
